import React, { useEffect } from "react";
import type { SkCanvas, SkImage, SkPaint } from "@shopify/react-native-skia";
import { Canvas, Image, Skia } from "@shopify/react-native-skia";
import { makeMutable, runOnUI } from "react-native-reanimated";
import { StyleSheet } from "react-native";

import { WINDOW_HEIGHT, WINDOW_WIDTH } from "../constants";
import { renderToTexture } from "../utils/renderToTexture";

import { RENDER_BACKGROUND } from "./config";

const { Paint } = Skia;

const backgroundTexture = makeMutable<SkImage | null>(null);

// this shader produces a color variation as you scroll
// mostly generated by chatgpt
const backgroundShader = Skia.RuntimeEffect.Make(`
uniform vec2 iResolution;  // Canvas width and height
uniform float offset;       // Offset to animate the gradient

// Smooth random noise function for organic transitions
float random(vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}

// Interpolated noise for smoother blending
float smoothNoise(vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);

    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));

    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

half4 main(vec2 fragCoord) {
    // Normalize coordinates to [0, 1]
    vec2 uv = fragCoord / iResolution  / 3;

    // Apply smooth UV distortion based on the offset value
    uv.x += sin(uv.y * 3.0 + offset * 0.002) * 0.5;
    uv.y += cos(uv.x * 3.0 + offset * 0.002) * 0.5;

    // Generate smooth noise to add texture to the gradient
    float n = smoothNoise(uv * 5.0);

    // Define soft, pastel-like colors
    vec3 color1 = vec3(0.95, 0.84, 0.76); // Soft peach
    vec3 color2 = vec3(0.76, 0.87, 0.93); // Light blue
    vec3 color3 = vec3(0.85, 0.78, 0.9);  // Lavender
    vec3 color4 = vec3(0.9, 0.85, 0.75);  // Beige

    // Blend the colors smoothly based on UV and noise
    vec3 color = mix(
        mix(color1, color2, smoothstep(0.0, 1.0, uv.x)),
        mix(color3, color4, smoothstep(0.0, 1.0, uv.y)),
        n
    );

    return half4(color, 1.0);  // Return the final blended color
}

`);

export function renderGradientIntoTexture(
  scrollOffset: number,
  paint: SkPaint | null
) {
  "worklet";

  if (!paint) {
    paint = Paint();
  }

  const texture = renderToTexture(
    WINDOW_WIDTH,
    WINDOW_HEIGHT,
    0,
    (canvas) => {
      paint.setShader(
        backgroundShader!.makeShader([
          WINDOW_WIDTH,
          WINDOW_HEIGHT,
          scrollOffset,
        ])
      );

      canvas.drawPaint(paint);
    },
    1
  );

  backgroundTexture.value = texture!.image;
}

export function createGradient() {
  "worklet";

  if (!RENDER_BACKGROUND) {
    return {
      onFrame() {},
    };
  }

  const paint = Paint();

  return {
    onFrame(ctx: SkCanvas, scrollOffset: number) {
      const prevTexture = backgroundTexture.value;

      renderGradientIntoTexture(scrollOffset, paint);

      if (!backgroundTexture.value) {
        return;
      }

      ctx.save();

      ctx.drawImage(backgroundTexture.value, 0, 0);

      ctx.restore();

      if (prevTexture) {
        prevTexture.dispose();
      }
    },
  };
}

export function Background() {
  useEffect(() => {
    if (!RENDER_BACKGROUND) {
      return;
    }

    runOnUI(() => {
      renderGradientIntoTexture(0, null);
    })();
  }, []);

  if (!RENDER_BACKGROUND) {
    return null;
  }

  return (
    <Canvas style={StyleSheet.absoluteFill}>
      <Image
        image={backgroundTexture}
        width={WINDOW_WIDTH}
        height={WINDOW_HEIGHT}
      />
    </Canvas>
  );
}
